package com.qkl.user.utils;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.OutputStream;
import java.util.Random;

public class CaptchaUtils {
    // 验证码字符集（排除易混淆字符）
    private static final String CODE_CHARSET = "23456789ABCDEFGHJKMNPQRSTUVWXYZabcdefghjkmnpqrstuvwxyz";
    private static final Random RANDOM = new Random();

    // ========== 可配置参数（根据图片尺寸调整，避免文字超出） ==========
    private static final int DEFAULT_LENGTH = 4; // 验证码长度（建议 4-5 位）
    private static final int DEFAULT_WIDTH = 140; // 图片宽度（字符越多，宽度需越大）
    private static final int DEFAULT_HEIGHT = 40; // 图片高度（建议 ≥ 字体大小 + 10）
    private static final int FONT_SIZE = 25; // 字体大小（建议 ≤ 图片高度的 70%，如 50*0.7=35）
    private static final int ROTATE_ANGLE = 20; // 最大旋转角度（±20°，避免过大导致超出）

    /**
     * 生成验证码图片（修复文字显示问题）
     */
    public static void generateCaptcha(OutputStream outputStream, StringBuilder code) throws Exception {
        generateCaptcha(outputStream, code, DEFAULT_LENGTH, DEFAULT_WIDTH, DEFAULT_HEIGHT);
    }

    /**
     * 自定义参数生成验证码
     * @param length 验证码长度（4-5位最佳）
     * @param width 图片宽度（长度×35 左右，如 4位→140，5位→175）
     * @param height 图片高度（建议 50-60）
     */
    public static void generateCaptcha(OutputStream outputStream, StringBuilder code, int length, int width, int height) throws Exception {
        // 1. 校验参数（避免尺寸过小导致文字无法显示）
        if (width < length * 30) throw new IllegalArgumentException("图片宽度不足，建议至少 " + length * 30 + "px");
        if (height < FONT_SIZE + 10) throw new IllegalArgumentException("图片高度不足，建议至少 " + (FONT_SIZE + 10) + "px");

        // 2. 创建图片缓冲区
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        Graphics2D g = image.createGraphics();

        // 3. 设置抗锯齿（让文字边缘更清晰）
        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

        // 4. 绘制背景（浅灰色，避免与文字混淆）
        g.setColor(new Color(248, 249, 250));
        g.fillRect(0, 0, width, height);

        // 5. 设置字体（粗体，避免过细导致模糊）
        Font font = new Font("Microsoft YaHei", Font.BOLD, FONT_SIZE);
        g.setFont(font);

        // 6. 计算每个字符的宽度（平均分配空间，避免拥挤）
        int charWidth = width / (length + 1); // 多留1份空间，避免左右边缘截断
        int startX = charWidth / 2; // 起始X坐标（左边留空，避免文字贴边）

        // 7. 生成并绘制每个字符（核心修复：合理计算坐标、控制旋转角度）
        code.setLength(0);
        for (int i = 0; i < length; i++) {
            // 随机选字符
            char c = CODE_CHARSET.charAt(RANDOM.nextInt(CODE_CHARSET.length()));
            code.append(c);

            // 随机文字颜色（深色，与浅背景对比强烈）
            g.setColor(new Color(RANDOM.nextInt(60), RANDOM.nextInt(60), RANDOM.nextInt(60)));

            // 计算字符绘制位置（关键：Y坐标设置为图片高度的 60%-70%，避免偏上/偏下）
            int x = startX + i * charWidth; // 每个字符的X坐标（平均分配）
            int y = height / 2 + FONT_SIZE / 3; // Y坐标（让文字垂直居中）

            // 随机旋转（±ROTATE_ANGLE，避免角度过大导致超出）
            int angle = RANDOM.nextInt(ROTATE_ANGLE * 2) - ROTATE_ANGLE;
            g.rotate(Math.toRadians(angle), x, y); // 以字符中心点为旋转中心

            // 绘制字符（X坐标微调整，避免拥挤）
            g.drawString(String.valueOf(c), x - 5, y);

            // 恢复旋转角度
            g.rotate(-Math.toRadians(angle), x, y);
        }

        // 8. 添加干扰线（不遮挡文字：线宽1px，颜色浅灰）
        for (int i = 0; i < 3; i++) {
            g.setColor(new Color(RANDOM.nextInt(200), RANDOM.nextInt(200), RANDOM.nextInt(200)));
            g.setStroke(new BasicStroke(1)); // 线宽1px，避免过粗遮挡文字
            g.drawLine(
                    RANDOM.nextInt(width / 5), RANDOM.nextInt(height),
                    width - RANDOM.nextInt(width / 5), RANDOM.nextInt(height)
            );
        }

        // 9. 添加噪点（小点，不遮挡文字）
        for (int i = 0; i < 80; i++) {
            g.setColor(new Color(RANDOM.nextInt(220), RANDOM.nextInt(220), RANDOM.nextInt(220)));
            g.fillOval(
                    RANDOM.nextInt(width), RANDOM.nextInt(height),
                    1, 1 // 噪点大小1px
            );
        }

        // 10. 释放资源并写入流
        g.dispose();
        ImageIO.write(image, "PNG", outputStream);
    }
}
